package ws.jdbc.concurrent.driver.sqlserver.tds.datatypes;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import ws.utils.ArrayUtil;

/**
 * Variable-length TYPE_INFO.
 *
 * <p>
 * <a href="http://msdn.microsoft.com/en-us/library/dd358341">Reference</a>
 * </p>
 * @author Wilson Santos, 36228 <wilson.santos@ua.pt>
 */
public class TypeInfoVarLenType extends TYPE_INFO {

  /** Length of this TYPE_INFO object. */
  private TYPE_VARLEN typevarlen;
  /**
   * Collation bytes.
   * 
   * <p>
   * <a href="http://msdn.microsoft.com/en-us/library/dd340437>Reference</a>
   * </p>
   */
  private byte[] collation = new byte[0];

  public TypeInfoVarLenType(byte varlentype) {
    this.dataType = varlentype;
  }

  public TypeInfoVarLenType(byte varlentype, TYPE_VARLEN typevarlen) {
    this.dataType = varlentype;
    this.typevarlen = typevarlen;
  }

  public TypeInfoVarLenType(byte varlentype, int type_varlen, byte[] collation) {
    this.dataType = varlentype;
    typevarlen = TYPE_VARLEN.create(varlentype, type_varlen);
    this.collation = collation;
  }

  /**
   * Read a variable-length TYPE_INFO object from the input stream.
   *
   * @param stream input stream.
   *
   * @return number of bytes read from the input stream.
   *
   * @throws IOException if an error occurs while reading from the data input stream.
   */
  public int read(final ByteBuffer stream) throws IOException {
    assert stream != null;

    typevarlen = TYPE_VARLEN.read(stream, dataType);
    int bytesRead = typevarlen.size();

    // read collation?
    if (VARLENTYPE.hasCollation(dataType)) {
      collation = new byte[5];
      stream.get(collation, 0, collation.length);
      bytesRead += collation.length;
    }
    return bytesRead;
  }

  @Override
  public int size() {
    return 1 + typevarlen.size() + collation.length;
  }

  /**
   * Get the instance representation as a byte array.
   *
   * @return instance representation as a byte array.
   */
  @Override
  public byte[] getBytes() {
    return ByteBuffer.allocate(size()).order(ByteOrder.LITTLE_ENDIAN).
            put(dataType).
            put(typevarlen.getBytes()).
            put(collation).
            array();
  }

  /**
   * TYPE_INFO string representation.
   *
   * @return variable-length TYPE_INFO fields as a string.
   */
  @Override
  public String toString() {
    return "TypeInfoVarLenType{"
            + "varlentype=" + Integer.toHexString(0x0FF & dataType)
            + ", type_varlen=" + typevarlen
            + ", collation=" + ArrayUtil.toHexadecimal(collation)
            + '}';
  }

  @Override
  public TYPE_VARLEN getTypeVarLen() {
    return typevarlen;
  }
}
